package czopyk.model.analysis;

import java.util.HashMap;
import java.util.Map;
import java.util.Observer;

import org.apache.log4j.Logger;

import czopyk.model.analysis.conditions.Condition;
import czopyk.model.factories.Utils;
import czopyk.model.structure.Observable;

import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.collection.Pair;

public class Analyzer extends Observable implements Observer {

	protected static final Logger l = Logger.getLogger("Analyzer");

	private EPServiceProvider epService;

	private final Map<Condition, Pair<Long, AnalyzerSlave>> conditionToId = new HashMap<Condition, Pair<Long, AnalyzerSlave>>();

	private int precision = 3;
	
	public Analyzer() {
		super();
		Configuration config = new Configuration();
		config.addEventTypeAutoName(this.getClass().getPackage().getName());
		epService = EPServiceProviderManager.getDefaultProvider(config);
	}

	public long getAnalysisStreamOfCondition(Condition c) {
		if (conditionToId.containsKey(c)) {
			return conditionToId.get(c).getFirst();
		}
		return registerCondition(c);
	}

	private long registerCondition(Condition c) {
		final long id = Utils.nextId();
		conditionToId.put(c, new Pair<Long, AnalyzerSlave>(id, new AnalyzerSlave(
				epService.getEPAdministrator(), c, id, this)));
		return id;
	}

	// caly ruch zdarzen przeplywa przez analyzer
	// stanowi on mediator
	public void update(java.util.Observable o, Object arg) {
		if (arg instanceof Event) {
			/*
			if (arg instanceof LoadReportEvent) {
				System.out.println(((LoadReportEvent)arg).getLoad());
			}
			*/
			epService.getEPRuntime().sendEvent(arg);
		}
		else if (arg instanceof Pair<?,?>) {
			// przekazanie informacji od analyzer slave'a
			notifyObservers(arg);
		}
	}
	
	public void setPrecision(Integer i) {
		if (i == null) {
			l.warn("Precision not set (null). Setting to default value 3.");
			i = 3;
		}
		precision = i;
	}

	public double cutPrecision(double val) {
		 int temp=(int)((val*Math.pow(10,precision)));
		 return (((double)temp)/Math.pow(10,precision));
	}

}
